package com.example.exercise.common.mvc;

import com.alibaba.fastjson.JSONObject;
import com.example.exercise.common.base.BaseResponse;
import com.example.exercise.common.net.WebUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import java.io.OutputStreamWriter;
import java.util.concurrent.TimeUnit;

/**
 * 限流拦截器
 */
@Component
public class RateLimitUserInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(RateLimitUserInterceptor.class);
    private static final int permitCount = 40;
    private static final int durationSecond = 2;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 每秒调用接口超过20次被认为非正常访问，对用户ip限流
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        if(o instanceof ResourceHttpRequestHandler) {
            //资源拦截跳过
            return true;
        }
        String key = "U_L:" + WebUtils.getRemoteAddr(httpServletRequest);
        String string = redisTemplate.opsForValue().get(key);
        Integer count = string == null? 0 : Integer.parseInt(string);
        if(count > permitCount){
            logger.warn("ip为" + key + "的用户频繁调用接口，属于非法访问！");
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpServletResponse.getOutputStream());
            BaseResponse<String> baseResponse = new BaseResponse<>();
            baseResponse.errMsg("访问频繁，请稍后再试");
            outputStreamWriter.write(JSONObject.toJSONString(baseResponse));
            outputStreamWriter.flush();
            outputStreamWriter.close();
            //异常访问，记录ip和path
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        if(o instanceof ResourceHttpRequestHandler) {
            //资源拦截跳过
            return;
        }
        String key = "USER_LIMIT:" + WebUtils.getRemoteAddr(httpServletRequest);
        redisTemplate.opsForValue().increment(key,1);
        redisTemplate.expire(key, durationSecond, TimeUnit.SECONDS);
    }
}
